Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reimplement security-webauthn on top of webauthn4j #44105

Merged
merged 9 commits into from
Dec 5, 2024

Conversation

FroMage
Copy link
Member

@FroMage FroMage commented Oct 25, 2024

This is following in the footsteps of the new vertx-auth-webauthn4j, which we're not using here because there was no point in converting our config to vertx config which converts to webauthn4j config.

I also took the opportunity to improve the docs and fix the API and endpoints to remove confusion.

As a result, this is not compatible with the previous API, here's the proposed migration guide, which I'll add in the migration notes as soon as we know where we merge this.

== Migration Guide

The quarkus-security-webauthn module has been reimplemented on top of WebAuthn4J. As a result, it is not binary or source compatible with the previous versions, and you must update the following code:

  • The Authenticator type
    • The Authenticator class (from Vert.x) is no longer used, and has been replaced functionally with WebAuthnCredentialRecord. It holds similar data to the previous class, but as it is a subtype of a WebAuthn4J type, accessing its content is slightly different.
    • Its replacing type WebAuthnCredentialRecord now has a getRequiredPersistedData() method which returns a RequiredPersistedData record holding all the data you need to persist to your data source (database, or anything persistent), to make it easier.
    • The static method WebAuthnCredentialRecord.fromRequiredPersistedData(RequiredPersistedData) allows you to turn your stored data into a WebAuthnCredentialRecord for the opposite operation.
  • If you had any JPA entities or database tables storing the old Authenticator format of data, you will need to update them to the new set of data. Open an issue if you need help for that.
  • The WebAuthnUserProvider type that you had to implement has been restructured:
    • findWebAuthnCredentialsByUserName() was renamed to findByUserName()
    • findWebAuthnCredentialsByCredID() was renamed to findByCredentialId()
    • updateOrStoreWebAuthnCredentials was split into the two methods it represented: update(String credentialId, long counter) and store(WebAuthnCredentialRecord credentialRecord)
  • Default endpoints:
    • /q/webauthn/login was renamed to /q/webauthn/login-options-challenge
    • /q/webauthn/register was renamed to /q/webauthn/register-options-challenge
    • /q/webauthn/callback was split into the two operations it represented: /q/webauthn/login and /q/webauthn/register. These endpoints are now disabled by default (for security reasons) and can be enabled using the quarkus.webauthn.enable-registration-endpoint and quarkus.webauthn.enable-login-endpoint configuration properties.
    • /q/webauthn/register now requires a username query parameter.
    • /.well-known/webauthn was added to return the list of allowed related origins
    • The user name for login and login-options-challenge is now optional
  • WebAuthnSecurity
    • Two methods have been added to WebAuthnSecurity: getLoginOptionsChallenge() and getRegisterOptionsChallenge() to make it easier to call and customise them.
    • The user name parameter for login() and loginOptionsChallenge() is now optional
    • The register() method now takes an additional userName parameter (due to the removal of the username cookie)
  • Configuration:
    • The quarkus.webauthn.require-resident-key (boolean defaulting to false) setting has been replaced by the quarkus.webauthn.resident-key (enum defaulting to REQUIRED)
    • The quarkus.webauthn.challenge-username-cookie-name setting has been removed along with its related cookie.
    • The quarkus.webauthn.load-metadata (boolean defaulting to false) setting has been added to control loading of FIDO metadata.
    • The quarkus.webauthn.user-presence-required (boolean defaulting to true) setting has been added to control the requirement of user presence.
    • The quarkus.webauthn.user-verification setting has changed default from DISCOURAGED to REQUIRED.
    • The quarkus.webauthn.timeout default has increased from 1 minute to 5 minutes as specified in the WebAuthn standard
    • The quarkus.webauthn.pub-key-cred-params setting has been renamed to quarkus.webauthn.public-key-credential-parameters
    • The quarkus.webauthn.origin setting has been renamed to quarkus.webauthn.origins (plural) and now allows more than one origin (as required by spec)
    • The new quarkus.webauthn.enable-registration-endpoint boolean configuration (defaults to false) enables the default registration endpoint.
    • The new quarkus.webauthn.enable-login-endpoint boolean configuration (defaults to false) enables the default login endpoint.
  • The verification of WebAuthn credential attestations may differ slightly for settings of quarkus.security.webauthn.attestation other than NONE (the default).
  • In the quarkus-test-security-webauthn test module:
    • The WebAuthnHardware contructor now requires a URL to represent the location of your endpoints, you can obtain in your test classes it using @TestHTTPResource URL url
    • The WebAuthnEndpointHelper.invokeRegistration method was renamed to obtainRegistrationChallenge
    • The WebAuthnEndpointHelper.invokeLogin method was renamed to obtainLoginChallenge
    • The WebAuthnEndpointHelper.invokeCallback method was split into the two operations it represented: WebAuthnEndpointHelper.invokeRegistration and WebAuthnEndpointHelper.invokeLogin
    • The WebAuthnEndpointHelper.invokeLogin and WebAuthnEndpointHelper.obtainLoginChallenge user name parameter is now optional
    • The WebAuthnEndpointHelper.invokeRegistration method now takes a userName parameter
  • JavaScript library:
    • The registerOnly method has been renamed to registerClientSteps
    • The loginOnly method has been renamed to loginClientSteps
    • The login and loginClientSteps method's user parameter is now optional
    • The constructor's registerPath has been renamed to registerOptionsChallengePath and has the default value /q/webauthn/register-options-challenge
    • The constructor's loginPath has been renamed to loginOptionsChallengePath and has the default value /q/webauthn/login-options-challenge
    • The constructor's callbackPath has been split into its two components registerPath (default value /q/webauthn/register) and loginPath (default value /q/webauthn/login
    • The constructor now accepts a csrf option of type JsonObject with two keys: header for the header name to use to add the CSRF token, and value for the CSRF token value. This is mostly useful when using quarkus-csrf and using custom endpoints that are protected by CSRF (unlike the default endpoints).

@quarkus-bot quarkus-bot bot added area/dependencies Pull requests that update a dependency file area/documentation area/testing labels Oct 25, 2024
@FroMage
Copy link
Member Author

FroMage commented Oct 25, 2024

Huh, I had completely forgotten I added WebAuthnHelper, I will document it in another PR, I'll open an issue.

@FroMage
Copy link
Member Author

FroMage commented Oct 25, 2024

And quickstarts are at quarkusio/quarkus-quickstarts#1470

@FroMage
Copy link
Member Author

FroMage commented Oct 25, 2024

WebAuthnHelper part is #44106

Copy link

github-actions bot commented Oct 25, 2024

🙈 The PR is closed and the preview is expired.

This comment has been minimized.

@maxandersen
Copy link
Member

Sorry I'm noob in webauthn - does this break users or allow them to coexist ? And what kind of users are affected - Quarkus app devs or/and ext dev?

@FroMage
Copy link
Member Author

FroMage commented Oct 28, 2024

The compatibility breakage is for users, but the module is in preview so we can break.

@FroMage
Copy link
Member Author

FroMage commented Oct 28, 2024

Quickstarts break is handled by the PR. The native one I need to look at.

@FroMage
Copy link
Member Author

FroMage commented Oct 28, 2024

Native should pass now.

This comment has been minimized.

This comment has been minimized.

@michalvavrik
Copy link
Member

Will check tomorrow evening.

@sberyozkin
Copy link
Member

Hi Steph, @FroMage, thanks for this major enhancement/refactoring, I have to do some homework to do a proper review, need to refresh some WebAuthn concepts and check webauthn4j docs, may take a bit of time, but I'm on it, cheers

&& config.attestation().get() == WebAuthnRunTimeConfig.Attestation.ENTERPRISE) {
TrustAnchorAsyncRepository something;
// FIXME: make config name configurable?
Optional<TlsConfiguration> webauthnTlsConfiguration = certificates.get("webauthn");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WebAuthn attestation certificate is not related to TLS.
Is it appropriate to use TlsConfigurationRegistry for webauthn attestation certificate?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's definitely not related to TLS, but for some reason the Quarkus certificate registry is called the TLS registry https://quarkus.io/guides/tls-registry-reference
This is just how every certificate list (and trust stores, private, public keys) are configured in Quarkus.
I do agree that the name implies a single purpose that is limiting, @cescoffier

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ha ha, @sberyozkin stopped me from using it from anything that is not TLS when I integrated this registry to OIDC. I agree, it would be nice to have Quarkus certificate registry, but there are things that doesn't make sense when you use it this way. Like handshakeTimeout, alpn and other stuff. I suppose it is fine for your use case because I think users does not configure this, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, @cescoffier himself told me to use this, to centralise everything 🤷

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FroMage TLS registry entries have properties related to TLS like handshake timeout, host verification options, reload related one, etc. If the attestation is not happening on the TLS path, it can be confusing for Quarkus WebAuthn users having to refer to TLS registry...
TLS registry is a great concept, but perhaps it can be enhanced over time to extend say TrustStoreRegistry instead of having to refer to it on the non-TLS paths

@michalvavrik
Copy link
Member

Sorry, it has been hectic week I must look later. But since @ynojima and @sberyozkin are going to have a look, I think it's not an issue. Great PR.

This comment has been minimized.

This comment has been minimized.

@FroMage
Copy link
Member Author

FroMage commented Dec 3, 2024

Rebased on main. This would be nice to merge before 3.18 ships, @michalvavrik @sberyozkin can I get a passing review?

This comment has been minimized.

This comment has been minimized.

@sberyozkin
Copy link
Member

@FroMage Can you please look at the Quickstart compilation issue and we can merge ? Indeed, it needs some settle-in time and for users to start experimenting, hard to make such a big refactoring perfect from the very start.

I'd also consider changing https://github.com/quarkusio/quarkus/blob/main/extensions/security-webauthn/runtime/src/main/resources/META-INF/quarkus-extension.yaml status to experimental (or highlight it in the docs) for you be able to change things without being concerned about breaking changes, while the extension settles in, but it is up to you.

@FroMage
Copy link
Member Author

FroMage commented Dec 5, 2024

@FroMage Can you please look at the Quickstart compilation issue and we can merge ? Indeed, it needs some settle-in time and for users to start experimenting, hard to make such a big refactoring perfect from the very start.

The quickstart PR is already waiting. It fails because it can't compile without this PR being merged. It's a chicken-egg problem.

I'd also consider changing https://github.com/quarkusio/quarkus/blob/main/extensions/security-webauthn/runtime/src/main/resources/META-INF/quarkus-extension.yaml status to experimental (or highlight it in the docs) for you be able to change things without being concerned about breaking changes, while the extension settles in, but it is up to you.

Sure, that makes sense.

Copy link

quarkus-bot bot commented Dec 5, 2024

Status for workflow Quarkus Documentation CI

This is the status report for running Quarkus Documentation CI on commit db12e82.

✅ The latest workflow run for the pull request has completed successfully.

It should be safe to merge provided you have a look at the other checks in the summary.

Warning

There are other workflow runs running, you probably need to wait for their status before merging.

@sberyozkin sberyozkin self-requested a review December 5, 2024 16:03
@sberyozkin sberyozkin added the triage/waiting-for-ci Ready to merge when CI successfully finishes label Dec 5, 2024
Copy link

quarkus-bot bot commented Dec 5, 2024

Status for workflow Quarkus CI

This is the status report for running Quarkus CI on commit db12e82.

Failing Jobs

Status Name Step Failures Logs Raw logs Build scan
Quickstarts Compilation - JDK 17 Compile Quickstarts Failures Logs Raw logs 🚧
Native Tests - Virtual Thread - Messaging Build ⚠️ Check → Logs Raw logs 🔍

You can consult the Develocity build scans.

Failures

⚙️ Quickstarts Compilation - JDK 17 #

- Failing: security-webauthn-quickstart security-webauthn-reactive-quickstart 

📦 security-webauthn-quickstart

Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.11.0:compile (default-compile) on project security-webauthn-quickstart: Compilation failure

📦 security-webauthn-reactive-quickstart

Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.11.0:compile (default-compile) on project security-webauthn-reactive-quickstart: Compilation failure


Flaky tests - Develocity

⚙️ Native Tests - Messaging1

📦 integration-tests/reactive-messaging-kafka

io.quarkus.it.kafka.KafkaConnectorIT.testRequestReply - History

  • iterable contents differ at index [2], expected: <reply-3> but was: <{"details":"Error id edb8cb3a-bc93-4331-ae9f-aa3fb9ba0561-1","stack":""}> - org.opentest4j.AssertionFailedError
org.opentest4j.AssertionFailedError: iterable contents differ at index [2], expected: <reply-3> but was: <{"details":"Error id edb8cb3a-bc93-4331-ae9f-aa3fb9ba0561-1","stack":""}>
	at io.quarkus.it.kafka.KafkaConnectorTest.testRequestReply(KafkaConnectorTest.java:112)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at io.quarkus.test.junit.QuarkusTestExtension.interceptTestMethod(QuarkusTestExtension.java:788)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

@sberyozkin sberyozkin merged commit fab189a into quarkusio:main Dec 5, 2024
53 of 55 checks passed
@quarkus-bot quarkus-bot bot added this to the 3.18 - main milestone Dec 5, 2024
@quarkus-bot quarkus-bot bot removed the triage/waiting-for-ci Ready to merge when CI successfully finishes label Dec 5, 2024
@FroMage FroMage deleted the webauthn4j branch December 6, 2024 09:36
@FroMage
Copy link
Member Author

FroMage commented Dec 6, 2024

Thanks.

@gsmet
Copy link
Member

gsmet commented Dec 6, 2024

I was going to ask for integrating something in the migration guide but it's already done! Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants